#include <cstddef>
#include <new>
#include <list>
#include <iostream>

template <class T>
class CustomAllocator
{
public:
    // type definitions
    typedef T value_type;
    typedef T* pointer;
    typedef const T* const_pointer;
    typedef T& reference;
    typedef const T& const_reference;
    typedef size_t size_type;
    typedef ptrdiff_t difference_type;

    // rebind
    template <class U>
    struct rebind
    {
        typedef CustomAllocator<U> other;
    };

    // address
    pointer address(reference value) const { return &value; }
    const_pointer address(const_reference value) const { return &value; }

    // max_size 
    size_type max_size() const throw()
    {
        return size_t(-1) / sizeof(T);
    }

    // allocate
    pointer allocate(size_type num, const void* = 0)
    {
        if (num > max_size()) {
            throw std::bad_alloc();
        }
        return static_cast<pointer>(::operator new(num * sizeof(T)));
    }

    // deallocate
    void deallocate(pointer p, size_type num)
    {
        ::operator delete(p);
    }

    // construct
    void construct(pointer p, const T& value)
    {
        ::new((void*)p) T(value);
    }

    // destroy
    void destroy(pointer p)
    {
        p->~T();
    }

    CustomAllocator() throw() {}
    CustomAllocator(const CustomAllocator&) throw() {}
    template <class U>
    CustomAllocator(const CustomAllocator<U>&) throw() {}
    ~CustomAllocator() {}

};

template <class T1, class T2>
inline bool operator==(const CustomAllocator<T1>&, const CustomAllocator<T2>&)
{
    return true;
}

template <class T1, class T2>
inline bool operator!=(const CustomAllocator<T1>&, const CustomAllocator<T2>&)
{
    return false;
}

int main(int argc, char *argv[])
{
    std::list<int, CustomAllocator<int> > l;

    l.push_front(1);
    l.push_front(2);
    l.push_front(2);
    l.push_front(2);
    l.push_front(2);
    
    std::cout << *l.begin() << std::endl;

    return 0;
}
